home *** CD-ROM | disk | FTP | other *** search
- /*
- * xah.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /*
- * X(Extract) A(rea) H(istogram)
- *
- */
- #include "xah.h"
-
- #define ON 1
- #define OFF 0
- #define DISABLE -1
-
- #define PROMPT_CUTOFF OFF /* prompt for cutoff value(ON/OFF) */
- #define DISPL_AOI OFF
- #define SCL_AOI OFF
- #define BIN_AOI ON /* binarize separate AOI (ON) or */
- /* binarize and scan same AOI (OFF) */
- /* disable binarization */
- #define LIM_AREA ON /* limit range of dom areas */
- #define WRITE_FILE ON /* prompt for outp file name */
- #define WRITE_ALL ON /* dump bub data to addit outp file */
- #define IP_TOOL ON
-
-
- #define MAX_ND 10000 /* max permiss. number of domains */
- #define NSQ 6 /* histogram limited to NSQ*sigma */
-
-
- #define DEFAULT 0 /* scale hist by min and max data */
- #define FIX_BINWD 1
- #define FIX_RANGE 2 /* restr. range, center at mean */
- #define FIX_INTERVAL 3 /* preset min AND max data */
-
- #define MIN_ND 5 /* min no domains for area histog */
-
- #define BUF_SZ 256 /* sz of input file buffer */
-
-
- #define SHOW_HIST
- #define DBG_HIST
- #define DEBUG
- #define S_DEBUG
-
-
- /*
- * Global Variables
- */
- static char HffPath[129]; /* path for HFF files */
- static char Scratch[32]; /* Scratch pad temporary buffer */
-
- static char *fn_prompt =
- {"...filename (.hdt)?"};
- static char hbuf[BUF_SZ], *phbuf = &hbuf[0]; /* file name buf for hdt output file */
- static char vbuf[BUF_SZ], *pvbuf = &vbuf[0]; /* file name buf for vin output file */
- static char gbuf[BUF_SZ], *pgbuf = &gbuf[0]; /* file name buf for gdt output file */
- extern char *optarg;
- extern int optind, opterr;
- extern short tiffInput; /* flag=0 if no ImageIn to set tags; else =1 */
-
-
- int SORT_STAT = 1; /* flag to ind sorted inp to eval_hist() */
-
- int CDYN = 1; /* flags ind data type */
- int X_SQ = 1; /* when set, eval hist of SQRT(area/mean_a) */
-
-
- /*
- * error message
- */
- void
- exitmess (prompt, status)
- char *prompt;
- int status;
- {
- printf (prompt);
- printf ("\n");
-
- exit (status);
- }
-
-
- void
- fail_alloc (char *str, int code)
- {
- printf ("\n...memory alloc for %s failed\n", str);
- exit (code);
- }
-
-
-
- /*
- * comparison of two elements in area array (for qsort)
- * here: array elements are of type unsigned int
- */
- int
- compare (a1, a2)
- int *a1;
- int *a2;
- {
- return ((int) SIGN (*a1 - *a2));
- }
-
-
- /* sort bubble structure on y, then x, coord */
- int
- bcomp (b1, b2)
- struct bubble *b1;
- struct bubble *b2;
- {
-
- if (b1->ctr.y < b2->ctr.y)
- return (-1);
- if (b1->ctr.y > b2->ctr.y)
- return (1);
- if (b1->ctr.x < b2->ctr.x)
- return (-1);
- if (b1->ctr.x > b2->ctr.x)
- return (1);
-
- return (0);
- }
-
-
-
- /*
- * usage of routine
- */
- void
- usage (char *progname)
- {
- progname = last_bs (progname);
- printf ("USAGE: %s inimg outimg [-a x1 y1 x2 y2] [-L]\n", progname);
- printf ("\n%s constructs area moments and area histogram,\n", progname);
- printf ("of image containing domains (\"blobs\");\n");
- printf ("the output image is a point pattern representing\n");
- printf ("the domain centroids; also evaluates histogram of\n");
- printf ("domain areas\n\n");
- printf ("ARGUMENTS:\n");
- printf (" inimg: input image filename (TIF)\n");
- printf (" outimg: output image filename (TIF)\n\n");
- printf ("OPTIONS:\n");
- printf (" -a x1 y1 x2 y2: upper left(x1, y1), lower right(x2, y2)\n");
- printf (" coords of area to scan (int);\n");
- printf (" default is area of imgin\n");
- printf (" -L: print Software License for this module\n");
- exit (1);
- }
-
- void
- main (int argc, char **argv)
- {
- struct bubble *ocbub, *rcbub, *cbub;
- unsigned int *oarea, *rarea, *area;
-
- double mean_a, sdev_a, skew_a;
- double del_a;
- int id, nd, ird;
- int c;
-
- float *farea;
-
-
- int BIN_METHOD = DEFAULT; /* select binning criterion */
- /* float *ahst; */
- struct Histo *ah;
-
- double foo = 1.0;
- int nparms = 3;
- FILE *wfp, *vfp, *gfp;
- Image *imgIn;
- Image *imgOut;
- int aoi_height;
- int aoi_width;
- int i_arg;
- int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
- char in_buf[IN_BUF_LEN];
-
- /*
- * cmd line options
- */
- static char *optstring = "a:L";
-
- /*
- * parse command line
- */
- optind = 3; /* set getopt to point to the start of the arg list */
- opterr = ON; /* give error messages */
-
-
- if (argc < 3)
- usage (argv[0]);
-
- while ((i_arg = getopt (argc, argv, optstring)) != EOF) {
- switch (i_arg) {
- case 'a':
- if (!sscanf (argv[optind - 1], "%d", &x1) || !sscanf (argv[optind], "%d", &y1)
- || !sscanf (argv[optind + 1], "%d", &x2) || !sscanf (argv[optind + 2], "%d", &y2)) {
- printf ("Error getting values for area to scan\n");
- printf ("Will attempt to scan entire picture\n");
- }
- break;
- case 'L':
- print_sos_lic ();
- exit (0);
- default:
- printf ("\ngetopt: unknown condition encountered\n");
- exit (1);
- break;
- }
- }
-
- /*
- * Read input image
- */
- imgIn = ImageIn (argv[1]);
-
- if (imgIn->bps == 8 && imgIn->spp == 3) {
- printf ("Got RGB image!!!\nInput image must be Grayscale or B&W!!\n");
- exit (1);
- }
- if (x1 == -1 || y1 == -1 || x2 == -1 || y2 == -1) {
- x1 = 0;
- y1 = 0;
- x2 = imgIn->width - 1;
- y2 = imgIn->height - 1;
- }
- else if (x1 < 0 || x1 >= imgIn->width
- || y1 < 0 || y1 >= imgIn->height
- || x2 < 0 || x2 >= imgIn->width
- || y2 < 0 || y2 >= imgIn->height
- || x1 > x2 || y1 > y2) {
- printf ("Invalid values for area to scan\n");
- printf ("Setting to size of input image\n");
- x1 = 0;
- y1 = 0;
- x2 = imgIn->width - 1;
- y2 = imgIn->height - 1;
- }
- aoi_height = y2 - y1 + 1;
- aoi_width = x2 - x1 + 1;
-
- /*
- * Allocate memory for output image
- */
- imgOut = ImageAlloc (aoi_height, aoi_width, imgIn->bps);
-
-
- /*
- * Draw a 255 border around image to eliminate
- * edge effects for line fills
- */
- draw_rect (0, 0, imgOut->width - 1, imgOut->height - 1, imgIn, WHITE);
-
- /*
- * measure and record domain areas, mark and record domain centroids
- */
- if ((ocbub = (struct bubble *) calloc (MAX_ND, sizeof (struct bubble))) == NULL)
- fail_alloc ("ocbub", 1);
- nd = ah_AOI (x1, y1, x2, y2, imgIn, imgOut, ocbub, MAX_ND);
-
- ImageOut (argv[2], imgOut);
- if ((oarea = (unsigned int *) calloc (MAX_ND, sizeof (unsigned int))) == NULL)
- fail_alloc ("oarea", 1);
-
- /*
- * sort area array
- */
-
- if (nd > MIN_ND) {
- extract_area (nd, oarea, &ocbub[0]);
- #ifdef DEBUG
- for (id = 0; id < nd; id++) {
- printf (" %6u", (ocbub + id)->area);
- if ((id + 1) % 8 == 0)
- printf ("\n");
- }
- #endif
-
- }
- else {
- printf ("\n...number of domains below lower limit of %d\n",
- MIN_ND);
-
- exit (1);
- }
-
-
- /*
- * evaluate moments
- */
-
- #ifdef DBG_HIST
- printf ("\n...evaluating mean area (area array):");
- #endif
-
- mean_a = eval_mean (nd, oarea);
- printf (" (raw) mean area: %6.2lf", mean_a);
-
-
- #ifdef DBG_HIST
- printf ("\n...evaluating rmsq (area array):");
- #endif
- sdev_a = eval_sdev (mean_a, nd, oarea);
- printf ("...rmsq dev: %6.2lf", sdev_a);
-
-
- #ifdef DBG_HIST
- printf ("\n...evaluating skew (area array):");
- #endif
- skew_a = 0.0;
- if (sdev_a > 0.01) {
- skew_a = eval_skew (mean_a, sdev_a, nd, oarea);
- printf ("...skew: %6.2lf", skew_a);
- }
- printf ("\n");
-
-
-
- /*
- * in imgOut, generate a display of the pattern marking sites
- * by UPW_TRIANGLE if the corresponding area exceeds mean_a, and
- * by a DNW_TRIANGLE otherwise
- */
- encode_ba (mean_a, sdev_a, ocbub, nd, imgOut, GRAY);
-
- /*
- * limit values in array oarea to those within a spread of NSQ*sdev_a
- * to eliminate artefacts
- */
- area = oarea;
- cbub = ocbub;
- if (LIM_AREA == ON) {
- if ((rarea = (unsigned int *) calloc (nd, sizeof (unsigned int))) == NULL)
- fail_alloc ("rarea", 1);
-
- if ((rcbub = (struct bubble *) calloc (nd, sizeof (struct bubble))) == NULL)
- fail_alloc ("rcbub", 1);
-
-
- ird = 0;
- for (id = 0; id < nd; id++) {
- del_a = (double) (*(oarea + id)) - mean_a;
- if (fabs (del_a) <= NSQ * sdev_a) {
- *(rarea + ird) = *(oarea + id);
- *(rcbub + ird) = *(ocbub + id);
- ird++;
- }
- }
- nd = ird;
- printf ("...%d domains within %d*std dev of mean area:\n",
- nd, NSQ);
-
- /*
- * handle memory alloc
- */
- rarea = (unsigned int *) realloc (rarea, nd * sizeof (unsigned int));
- rcbub = (struct bubble *) realloc (rcbub, nd * sizeof (struct bubble));
-
- area = rarea;
- cbub = rcbub;
-
-
- #ifdef DEBUG
- printf ("...domain areas within %d*rmsq of mean...\n", NSQ);
- for (id = 0; id < nd; id++) {
- printf (" %6u", (cbub + id)->area);
- if ((id + 1) % 8 == 0)
- printf ("\n");
- }
- printf ("\n");
- #endif
- }
- /*
- * bin data into histogram
- */
- #ifdef DBG_HIST
- printf ("\n...evaluate area histogram...\n");
- #endif
-
- printf ("...sorting %d domains by area...\n", nd);
- #if defined(LINUX)
- qsort (area, (size_t) nd, sizeof (unsigned int), (__compar_fn_t) compare);
- #else
- qsort (area, (size_t) nd, sizeof (unsigned int), compare);
- #endif
-
-
- #ifdef S_DEBUG
- printf ("...domain area array after sorting...\n");
- for (id = 0; id < nd; id++) {
- printf (" %6u", *(area + id));
- if ((id + 1) % 8 == 0)
- printf ("\n");
- }
- #endif
-
-
- /*
- * for generality's sake, convert to float
- */
- if ((farea = (float *) calloc (nd, sizeof (float))) == NULL)
- fail_alloc ("farea", 1);
-
- for (id = 0; id < nd; id++)
- *(farea + id) = (float) (*(area + id));
-
-
- /*
- * for domain coarsening data
- */
- if (CDYN == 1) {
- for (id = 0; id < nd; id++) {
- *(farea + id) /= (float) (mean_a);
- if (X_SQ == ON) {
- *(farea + id) = (float) sqrt (*(farea + id));
- }
- }
- BIN_METHOD = FIX_INTERVAL;
- }
- ah = eval_hist (BIN_METHOD, farea, nd, 1);
-
- ah->mean = mean_a;
- ah->sdev = sdev_a;
- ah->skew = skew_a;
- printf ("\n\n...histogram of %d domain areas (norm by raw mean):\n", nd);
- printf (" max(pix): %6.2f", ah->amax);
- printf (" min(pix): %6.2f", ah->amin);
- printf (" bin_w(pix): %6.3f\n", ah->bw);
- printf (" hist mean(pix): %6.2lf\n", ah->hmean);
-
-
- /*
- * write histogram data to file
- */
- if (WRITE_FILE == ON) {
- c = 0;
- printf ("\n...write files (.hdt, .vin and .gdt)?(y/n)");
- while ((c != 'y') && (c != 'n'))
- c = readlin (in_buf);
-
- if (c == 'y') {
- printf ("...enter fn [drive:][\\directory\\]: ");
- readlin (in_buf);
- strcpy (hbuf, in_buf);
- strcpy (vbuf, in_buf);
- strcpy (gbuf, in_buf);
- strcat (hbuf, ".hdt");
- strcat (vbuf, ".vin");
- strcat (gbuf, ".gdt");
-
- if ((wfp = fopen (hbuf, "w")) == NULL) {
- fprintf (stderr, "could not open output file %s\n", hbuf);
- exit (1);
- }
-
- printf ("writing data file: %s\n", hbuf);
- write_aoi_data (wfp, (float) foo, nparms, ah, X_SQ);
-
- if ((gfp = fopen (gbuf, "w")) == NULL) {
- fprintf (stderr, "could not open output file %s\n", gbuf);
- exit (1);
- }
-
- #if defined(LINUX)
- qsort (cbub, nd, sizeof (struct bubble), (__compar_fn_t) bcomp);
- #else
- qsort (cbub, nd, sizeof (struct bubble), bcomp);
- #endif
- printf ("writing data file: %s\n", gbuf);
- write_bub_data (gfp, (float) foo, nparms, &cbub[0], nd);
-
- if ((vfp = fopen (vbuf, "w")) == NULL) {
- fprintf (stderr, "could not open output file %s\n", vbuf);
- exit (1);
- }
-
- printf ("writing data file: %s\n", vbuf);
- write_vin_file (vfp, nd, x1, y1, x2, y2, cbub);
-
- fclose (wfp);
- fclose (vfp);
- fclose (gfp);
- }
- }
-
-
- /*
- * release resources
- */
-
-
-
- if (LIM_AREA == ON) {
- free (rarea);
- free (rcbub);
- }
- free (ocbub);
- free (oarea);
- free (farea);
- free (ah->ph);
- free (ah); /* alloc in aoi_hist */
-
- }
-
- /*
- * extract area values into separate array
- */
- void
- extract_area (int nd, unsigned int *area, struct bubble *cbub)
- {
- int id;
-
- for (id = 0; id < nd; id++)
- *(area + id) = (cbub + id)->area;
- }
-